/*
 * Copyright © 2017-2023 TemplateFactory(xiaoymin@foxmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.github.xiaoymin.maven;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.github.xiaoymin.docker.parameter.DockerDeploy;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 针对Docker容器化部署的插件，使用该插件有几个前提：
 * <p>1、该项目目录下必须包含Dockerfile构建文件</p>
 * <p>2、在项目的pom.xml中增加配置，详见README.md说明文档</p>
 * @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
 * 2021/05/14 16:21
 * @since template-factory 1.0
 */
@Mojo(name = "docker", defaultPhase = LifecyclePhase.NONE, requiresDependencyResolution = ResolutionScope.NONE)
public class DockerDeployMavenMojo extends AbstractMojo {
    
    /**
     * Maven Project.
     *
     */
    @Parameter(property = "project", required = true, readonly = true)
    private MavenProject project;
    
    /**
     * 是否跳过不执行该组件
     */
    @Parameter(property = "skip", required = false, defaultValue = "false")
    private Boolean skip = false;
    
    /**
     * 部署指定条件
     */
    @Parameter(property = "deploys", required = true)
    private Map<String, DockerDeploy> deploys;
    
    Logger logger = LoggerFactory.getLogger(DockerDeployMavenMojo.class);
    
    /**
     * 主要执行逻辑：
     * <ul>
     *     <li>1、开发者需要在该插件中配置deploys节点信息</li>
     * </ul>
     * @throws MojoExecutionException
     * @throws MojoFailureException
     */
    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        if (!skip) {
            if (CollectionUtil.isNotEmpty(deploys)) {
                String artifactId = project.getArtifactId();
                // 判断deploys配置节点中是否包含该项目
                if (deploys.containsKey(artifactId)) {
                    DockerDeploy dockerDeploy = deploys.get(artifactId);
                    if (dockerDeploy != null && dockerDeploy.validate()) {
                        logger.info("docker deploy plugin start working......");
                        // logger.info("\r\nharbor:{}\r\ngroup:{}\r\nname:{}\r\ntag:{}",dockerDeploy.getHarbor(),dockerDeploy.getGroup(),dockerDeploy.getName(),dockerDeploy.getTag());
                        File homeFile = project.getBasedir();
                        // 判断该目录下是否包含Dockerfile文件
                        File[] dockerFiles = homeFile.listFiles(((dir, name) -> StrUtil.equalsIgnoreCase(name, "Dockerfile")));
                        if (ArrayUtil.isNotEmpty(dockerFiles)) {
                            logger.info("project location:{}", project.getBasedir().getAbsolutePath());
                            // 执行Docker build命令
                            StringBuilder buildCmd = new StringBuilder();
                            buildCmd.append("docker build -t ").append(dockerDeploy.getHarbor()).append("/").append(dockerDeploy.getGroup())
                                    .append("/").append(dockerDeploy.getName()).append(":").append(dockerDeploy.getTag()).append(" .");
                            logger.info("docker build start,cmd:{}", buildCmd);
                            exec(buildCmd.toString(), project.getBasedir());
                            StringBuilder pushCmd = new StringBuilder();
                            pushCmd.append("docker push ").append(dockerDeploy.getHarbor()).append("/").append(dockerDeploy.getGroup())
                                    .append("/").append(dockerDeploy.getName()).append(":").append(dockerDeploy.getTag());
                            logger.info("docker push start,cmd:{}", pushCmd);
                            exec(pushCmd.toString(), project.getBasedir());
                            logger.info("docker deploy finished.");
                        } else {
                            throw new RuntimeException("No Dockerfile was found. You must store a Dockerfile in your project directory!!!");
                        }
                    }
                }
            }
        }
    }
    
    /**
     * 执行命令
     * @param cmd 命令
     * @param baseFile 目录
     */
    private void exec(String cmd, File baseFile) {
        try {
            // 获取系统环境变量
            Map<String, String> env = System.getenv();
            List<String> envArrs = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(env)) {
                for (Map.Entry<String, String> envEntry : env.entrySet()) {
                    envArrs.add(envEntry.getKey() + "=" + envEntry.getValue());
                }
            }
            Process process = Runtime.getRuntime().exec(cmd, envArrs.toArray(new String[]{}), baseFile);
            log(process.getInputStream(), "i");
            log(process.getErrorStream(), "e");
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
    
    /**
     * 日志输出
     * @param inputStream
     */
    private void log(InputStream inputStream, String type) {
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                logger.info(type + "->" + line);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            IoUtil.close(bufferedReader);
        }
    }
}
